﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace laohan.Common.USB.DeviceNotify
{
	public class WindowsDeviceNotifier : IDeviceNotifier
	{
		private DevNotifyNativeWindow mNotifyWindow;

		private bool mEnabled = true;

		private readonly DevBroadcastDeviceinterface mDevInterface = new DevBroadcastDeviceinterface(new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED"));

		private SafeNotifyHandle mDevInterfaceHandle;

		public bool Enabled
		{
			get
			{
				return mEnabled;
			}
			set
			{
				mEnabled = value;
			}
		}

		public event EventHandler<DeviceNotifyEventArgs> OnDeviceNotify;

		public WindowsDeviceNotifier()
		{
			mNotifyWindow = new DevNotifyNativeWindow(OnHandleChange, OnDeviceChange);
		}

		private void OnHandleChange(IntPtr newWindowHandle)
		{
			RegisterDeviceInterface(newWindowHandle);
		}

		internal bool RegisterDeviceInterface(IntPtr windowHandle)
		{
			if (mDevInterfaceHandle != null)
			{
				mDevInterfaceHandle.Dispose();
				mDevInterfaceHandle = null;
			}
			if (windowHandle != IntPtr.Zero)
			{
				mDevInterfaceHandle = Win32API.RegisterDeviceNotification(windowHandle, mDevInterface, 0);
				if (mDevInterfaceHandle != null && !mDevInterfaceHandle.IsInvalid)
				{
					return true;
				}
				return false;
			}
			return false;
		}

		private void OnDeviceChange(ref Message m)
		{
			if (!mEnabled || m.LParam.ToInt32() == 0)
			{
				return;
			}
			EventHandler<DeviceNotifyEventArgs> onDeviceNotify = this.OnDeviceNotify;
			if (onDeviceNotify != null)
			{
				DevBroadcastHdr devBroadcastHdr = new DevBroadcastHdr();
				Marshal.PtrToStructure(m.LParam, devBroadcastHdr);
				DeviceNotifyEventArgs deviceNotifyEventArgs;
				switch (devBroadcastHdr.DeviceType)
				{
					case DeviceType.Volume:
					case DeviceType.Port:
					case DeviceType.DeviceInterface:
						deviceNotifyEventArgs = new WindowsDeviceNotifyEventArgs(devBroadcastHdr, m.LParam, (EventType)m.WParam.ToInt32());
						break;
					default:
						deviceNotifyEventArgs = null;
						break;
				}
				if (deviceNotifyEventArgs != null)
				{
					onDeviceNotify(this, deviceNotifyEventArgs);
				}
			}
		}

		~WindowsDeviceNotifier()
		{
			if (mNotifyWindow != null)
			{
				mNotifyWindow.DestroyHandle();
			}
			mNotifyWindow = null;
			if (mDevInterfaceHandle != null)
			{
				mDevInterfaceHandle.Dispose();
			}
			mDevInterfaceHandle = null;
		}
	}
}
